package io.vertx.core.ioc;

import com.google.gson.Gson;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import io.lettuce.core.RedisClient;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.codec.ByteArrayCodec;
import io.vertx.core.Context;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpClient;
import io.vertx.pgclient.PgConnectOptions;
import io.vertx.pgclient.PgPool;
import io.vertx.sqlclient.PoolOptions;

public class B
{
    private static ConcurrentMap<Context, B> beanMap = new ConcurrentHashMap<>();
    private static Vertx vertx;

    private Map<Class, Object> instance = new HashMap<>();

    public static void init(Vertx vertx) {
        B.vertx = vertx;
    }
    public static void close() {
        vertx = null;
        beanMap.values().forEach(b -> b.doDestroy());
        beanMap.clear();
    }

    private B() {
    }

    public static B get() {
        final Context c = Vertx.currentContext();
        if(c == null) {
            throw new RuntimeException("should be called in verticle ");
        }
        return beanMap.computeIfAbsent(c, context -> new B());
    }

    private static <T> Object createBeanIns(Class<T> aClass) {
        try {
            Object o = aClass.newInstance();
            if (o instanceof VertxComponent) {
                ((VertxComponent) o).init(B.get());
            }
            return o;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public <T> T getInstance(Class<T> type) {
        return (T) instance.computeIfAbsent(type, B::createBeanIns);
    }

    private void doDestroy() {
        httpClient.destroy();
        redisConnection.close();
        pgPool.close();
    }




    private static Gson gson = new Gson();

    public Gson gson() {
        return gson;
    }

    private static RedisClient redisClient = RedisClient.create("redis://myserver/0");

    private static StatefulRedisConnection<byte[], byte[]> redisConnection = redisClient.connect(new ByteArrayCodec());

    public StatefulRedisConnection<byte[], byte[]> redisConnection() {
        return redisConnection;
    }

    private Lazy<HttpClient> httpClient = new Lazy<HttpClient>()
    {

        @Override
        protected HttpClient create() {
            return vertx.createHttpClient();
        }
    };

    public HttpClient httpCLient() {
        return httpClient.get();
    }

    private PgPool pgPool = PgPool.pool(vertx, new PgConnectOptions().setHost("myserver"), new PoolOptions().setMaxSize(2));
    public PgPool pgPool() {
        return pgPool;
    }


}
